#include "EnumGenerator.h"

#include "HeadFile.h"
#include "MetaGenerator.h"

CEnumGenerator::CEnumGenerator(CHeadFile *InContext)
{
    Context = InContext;
    EnumInfo = std::make_shared<CEnumInfo>();
}

void CEnumGenerator::Generate()
{
    //skipt RENUM
    {
        auto Token = Context->GetCurrentToken();
        if(Token->Type == ETokenType::RENUM)
        {
            Context->GotoNextToken();
        }
        else
        {
            Context->RaiseError(Token, U"expect 'RENUM'");
        }
    }

    //read meta 
    {
        auto MetaGenerator = std::make_shared<CMetaGenerator>(Context);
        MetaGenerator->Generate();
        EnumInfo->Meta = MetaGenerator->Result;
    }

    //skip enum
    {
        auto Token = Context->GetCurrentToken();
        if(Token->Type == ETokenType::Enum)
        {
            Context->GotoNextToken();
        }
        else
        {
            Context->RaiseError(Token, U"expect 'enum'");
        }
    }

    //skip class
    {
        auto Token = Context->GetCurrentToken();
        if(Token->Type == ETokenType::Class)
        {
            Context->GotoNextToken();
        }
        else
        {
            Context->RaiseError(Token, U"expect 'class' after enum");
        }
    }

    //read name
    {
        auto Token = Context->GetCurrentToken();
        if(Token->Type == ETokenType::Identifier)
        {
            EnumInfo->Name = std::get<C32String>(Token->LiteralValue.value()).ToUtf8();
            Context->GotoNextToken();
        }
        else
        {
            Context->RaiseError(Token, U"expect identifier");
        }
    }

    //skip '{'
    {
        auto Token = Context->GetCurrentToken();
        if(Token->Type == ETokenType::LeftBrace)
        {
            Context->GotoNextToken();
        }
        else
        {
            Context->RaiseError(Token, U"expect '{'");
        }
    }

    //read enum value
    {
        auto Token = Context->GetCurrentToken();
        while(Token->Type != ETokenType::RightBrace)
        {
            if(Token->Type == ETokenType::Identifier)
            {
                auto Name = std::get<C32String>(Token->LiteralValue.value()).ToUtf8();
                EnumInfo->Values.push_back(Name);
                Context->GotoNextToken();

                //skip '='
                {
                    auto NextToken = Context->GetCurrentToken();
                    if(NextToken->Type == ETokenType::Assign)
                    {
                        Context->GotoNextToken();

                        //until comma
                        while(NextToken->Type != ETokenType::Comma)
                        {
                            Context->GotoNextToken();
                            NextToken = Context->GetCurrentToken();
                        }

                        Context->GotoNextToken();
                        Token = Context->GetCurrentToken();
                        continue;
                    }
                    else if(NextToken->Type == ETokenType::Comma)
                    {
                        Context->GotoNextToken();
                        Token = Context->GetCurrentToken();
                        continue;
                    }
                    else if(NextToken->Type == ETokenType::RightBrace)
                    {
                        break;
                    }
                    else
                    {
                        Context->RaiseError(NextToken, U"expect '=' or ','");
                    }
                }
            }
            else
            {
                Context->RaiseError(Token, U"expect identifier");
            }

            Token = Context->GetCurrentToken();
        }
    }

    //skip '}'
    {
        auto Token = Context->GetCurrentToken();
        if(Token->Type == ETokenType::RightBrace)
        {
            Context->GotoNextToken();
        }
        else
        {
            Context->RaiseError(Token, U"expect '}'");
        }
    }

}
